package com.blog.cmrpersonalblog.service.impl;

import com.blog.cmrpersonalblog.config.RankingConfig;
import com.blog.cmrpersonalblog.dto.ranking.respnose.HeatScoreInfo;
import com.blog.cmrpersonalblog.service.HeatScoreCalculator;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

/**
 * 热度分数计算器实现
 */
@Slf4j
@Service
public class HeatScoreCalculatorImpl implements HeatScoreCalculator {
    
    @Resource
    private RankingConfig rankingConfig;
    
    @Override
    public Long calculateArticleHeatScore(
        Integer viewCount,
        Integer likeCount,
        Integer collectCount,
        Integer commentCount,
        Integer shareCount,
        LocalDateTime publishTime
    ) {
        HeatScoreInfo info = calculateArticleHeatScoreDetail(
            viewCount, likeCount, collectCount, commentCount, shareCount, publishTime
        );
        // 四舍五入转换为整数
        return Math.round(info.getTotalScore());
    }
    
    @Override
    public HeatScoreInfo calculateArticleHeatScoreDetail(
        Integer viewCount,
        Integer likeCount,
        Integer collectCount,
        Integer commentCount,
        Integer shareCount,
        LocalDateTime publishTime
    ) {
        HeatScoreInfo info = new HeatScoreInfo();
        
        // 获取权重配置
        RankingConfig.HeatWeightConfig weight = rankingConfig.getHeatWeight();
        
        // 处理null值
        viewCount = viewCount == null ? 0 : viewCount;
        likeCount = likeCount == null ? 0 : likeCount;
        collectCount = collectCount == null ? 0 : collectCount;
        commentCount = commentCount == null ? 0 : commentCount;
        shareCount = shareCount == null ? 0 : shareCount;
        
        // 计算各项分数
        double viewScore = viewCount * weight.getViewWeight();
        double likeScore = likeCount * weight.getLikeWeight();
        double collectScore = collectCount * weight.getCollectWeight();
        double commentScore = commentCount * weight.getCommentWeight();
        double shareScore = shareCount * weight.getShareWeight();
        
        // 计算基础分数
        double baseScore = viewScore + likeScore + collectScore + commentScore + shareScore;
        
        // 计算时间衰减系数
        double timeDecayFactor = calculateTimeDecayFactor(publishTime);
        
        // 计算最终分数（基础分数 * 时间衰减系数）
        double totalScore = baseScore * timeDecayFactor;
        
        // 填充详情
        info.setViewScore(viewScore);
        info.setLikeScore(likeScore);
        info.setCollectScore(collectScore);
        info.setCommentScore(commentScore);
        info.setShareScore(shareScore);
        info.setTimeDecayFactor(timeDecayFactor);
        info.setTotalScore(totalScore);
        
        // 计算发布天数
        if (publishTime != null) {
            long days = ChronoUnit.DAYS.between(publishTime, LocalDateTime.now());
            info.setDaysSincePublish((int) days);
        }
        
        return info;
    }
    
    @Override
    public Long calculateAuthorInfluenceScore(
        Integer fansCount,
        Integer articleCount,
        Integer totalViewCount,
        Integer totalLikeCount,
        Integer totalCollectCount
    ) {
        HeatScoreInfo info = calculateAuthorInfluenceScoreDetail(
            fansCount, articleCount, totalViewCount, totalLikeCount, totalCollectCount
        );
        // 四舍五入转换为整数
        return Math.round(info.getTotalScore());
    }
    
    @Override
    public HeatScoreInfo calculateAuthorInfluenceScoreDetail(
        Integer fansCount,
        Integer articleCount,
        Integer totalViewCount,
        Integer totalLikeCount,
        Integer totalCollectCount
    ) {
        HeatScoreInfo info = new HeatScoreInfo();
        
        // 获取权重配置
        RankingConfig.HeatWeightConfig weight = rankingConfig.getHeatWeight();
        
        // 处理null值
        fansCount = fansCount == null ? 0 : fansCount;
        articleCount = articleCount == null ? 0 : articleCount;
        totalViewCount = totalViewCount == null ? 0 : totalViewCount;
        totalLikeCount = totalLikeCount == null ? 0 : totalLikeCount;
        totalCollectCount = totalCollectCount == null ? 0 : totalCollectCount;
        
        // 计算粉丝分数
        double fansScore = fansCount * weight.getFansWeight();
        
        // 计算文章数分数
        double articleCountScore = articleCount * weight.getArticleCountWeight();
        
        // 计算内容质量分数（基于总浏览、点赞、收藏）
        double contentQualityScore = 
            totalViewCount * weight.getViewWeight() * 0.1 +  // 降低浏览量权重
            totalLikeCount * weight.getLikeWeight() * 0.5 +
            totalCollectCount * weight.getCollectWeight() * 0.5;
        
        // 计算总分
        double totalScore = fansScore + articleCountScore + contentQualityScore;
        
        // 填充详情
        info.setFansScore(fansScore);
        info.setArticleCountScore(articleCountScore);
        info.setViewScore(totalViewCount * weight.getViewWeight() * 0.1);
        info.setLikeScore(totalLikeCount * weight.getLikeWeight() * 0.5);
        info.setCollectScore(totalCollectCount * weight.getCollectWeight() * 0.5);
        info.setAuthorInfluenceScore(totalScore);
        info.setTotalScore(totalScore);
        
        return info;
    }
    
    @Override
    public Double calculateTimeDecayFactor(LocalDateTime publishTime) {
        if (publishTime == null) {
            return 1.0;
        }
        
        // 获取配置
        RankingConfig.HeatWeightConfig weight = rankingConfig.getHeatWeight();
        Double decayFactor = weight.getTimeDecayFactor();
        Integer maxDecayDays = weight.getMaxDecayDays();
        
        // 计算发布天数
        long daysSincePublish = ChronoUnit.DAYS.between(publishTime, LocalDateTime.now());
        
        // 如果是未来时间或当天，返回1.0
        if (daysSincePublish <= 0) {
            return 1.0;
        }
        
        // 如果超过最大衰减天数，使用最大衰减天数计算
        if (daysSincePublish > maxDecayDays) {
            daysSincePublish = maxDecayDays;
        }
        
        // 计算衰减系数：decayFactor ^ daysSincePublish
        // 例如：0.95 ^ 7 ≈ 0.698（一周后约70%）
        //      0.95 ^ 30 ≈ 0.215（一个月后约21%）
        double factor = Math.pow(decayFactor, daysSincePublish);
        
        log.debug("时间衰减计算: 发布{}天前, 衰减系数={}", daysSincePublish, factor);
        
        return factor;
    }
}

